package org.avenger.bucky.manager;

import com.alibaba.fastjson.JSONObject;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.Block;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.avenger.bucky.constant.Collection;
import org.avenger.bucky.handler.TestQuestionHandler;
import org.avenger.bucky.model.IgnoreOption;
import org.avenger.bucky.model.Option;
import org.avenger.bucky.model.TestQuestion;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;

/**
 * 用于处理Mongodb
 */
public class MongoManager {

    private static Logger log = LogManager.getLogger(MongoManager.class);

    /**
     * ip
     */
    private String ip;

    /**
     * 端口
     */
    private int port;

    /**
     * 数据库
     */
    private String database;

    private MongoClient mongoClient;

    private MongoDatabase mongoDatabase;

    public MongoManager() {
    }

    public MongoManager(String ip, int port, String database) {
        this.ip = ip;
        this.port = port;
        this.database = database;

        this.mongoClient = new MongoClient(ip, port);
        this.mongoDatabase = mongoClient.getDatabase(database);
    }

    /**
     * 根据题型，查找TestQuestion类型对象列表。如果TestQuestion为空，则返回所有TestQuestion类型对象
     * @param questionType
     * @return
     */
    public List<TestQuestion> findByQuestionType(String questionType){
        MongoCollection<org.bson.Document> mongoCollection = this.mongoDatabase.getCollection(Collection.TEST_QUESTION);
        BasicDBObject basicDBObject = new BasicDBObject();
        if (StringUtils.isNotEmpty(questionType)){
//        String whereStr = "function (){return this.in_use == '是' && this.question_type == '" + questionType + "'};";
            String whereStr = "function (){return this.question_type == '" + questionType + "'};";
            basicDBObject.put("$where", whereStr);
        }
        FindIterable<org.bson.Document> findIterable= mongoCollection.find(basicDBObject);
        MongoCursor<Document> mongoCursor = findIterable.iterator();
        TestQuestion testQuestion;
        List<TestQuestion> testQuestionList = new ArrayList<TestQuestion>();
        while (mongoCursor.hasNext()){
            String json = mongoCursor.next().toJson();
            testQuestion = JSONObject.parseObject(json, TestQuestion.class);
            testQuestionList.add(testQuestion);
        }
        mongoCursor.close();
        return testQuestionList;
    }

    /**
     * 查找所有TestQuestion类型的对象
     * @return
     */
    public List<TestQuestion> findAll(){
        MongoCollection<org.bson.Document> mongoCollection = this.mongoDatabase.getCollection(Collection.TEST_QUESTION);
        FindIterable<org.bson.Document> findIterable= mongoCollection.find();
        MongoCursor<Document> mongoCursor = findIterable.iterator();
        TestQuestion testQuestion;
        List<TestQuestion> testQuestionList = new ArrayList<TestQuestion>();
        while (mongoCursor.hasNext()){
            String json = mongoCursor.next().toJson();
            testQuestion = JSONObject.parseObject(json, TestQuestion.class);
            testQuestionList.add(testQuestion);
        }
        mongoCursor.close();
        return testQuestionList;
    }

    /**
     * 根据集合名称，查找文档列表
     * @return
     */
    public List findByCollectionName(String collectionName){
        MongoCollection<org.bson.Document> mongoCollection = this.mongoDatabase.getCollection(collectionName);
        FindIterable<org.bson.Document> findIterable= mongoCollection.find();
        MongoCursor<Document> mongoCursor = findIterable.iterator();
        Object object;
        List list = new ArrayList();
        while (mongoCursor.hasNext()){
            String json = mongoCursor.next().toJson();
            object = JSONObject.parseObject(json, Object.class);
            list.add(object);
        }
        mongoCursor.close();
        return list;
    }

    /**
     * 查找集合collectionName中的所有文档
     * @param collectionName
     * @return
     */
    public List<TestQuestion> findAll(String collectionName){
        MongoCollection<org.bson.Document> mongoCollection = this.mongoDatabase.getCollection(collectionName);
        FindIterable<org.bson.Document> findIterable= mongoCollection.find();
        MongoCursor<Document> mongoCursor = findIterable.iterator();
        TestQuestion testQuestion;
        List<TestQuestion> testQuestionList = new ArrayList<TestQuestion>();
        while (mongoCursor.hasNext()){
            String json = mongoCursor.next().toJson();
            testQuestion = JSONObject.parseObject(json, TestQuestion.class);
            testQuestionList.add(testQuestion);
        }
        mongoCursor.close();
        return testQuestionList;
    }

    /**
     * 加载忽略的选项：查询ignore_option中的所有文档，只返回content属性
     * @return
     */
    public List<String> findContentInIgnoreOptionTable(){
        MongoCollection<org.bson.Document> ignoreOptionMongoCollection = this.mongoDatabase.getCollection(Collection.IGNORE_OPTION);
        FindIterable<org.bson.Document> ignoreOptionFindIterable = ignoreOptionMongoCollection.find();
        MongoCursor<Document> ignoreOptionMongoCursor = ignoreOptionFindIterable.iterator();
        List<String> ignoreOptionList = new ArrayList<>();
        while (ignoreOptionMongoCursor.hasNext()){
            String json = ignoreOptionMongoCursor.next().toJson();
            IgnoreOption ignoreOption = JSONObject.parseObject(json, IgnoreOption.class);
            ignoreOptionList.add(ignoreOption.getContent());
        }
        return ignoreOptionList;
    }

    /**
     * 根据ObjectId，查找TestQuestion对象
     * @param objectId
     * @return
     */
    public TestQuestion findByObjectId(ObjectId objectId){
        MongoCollection<org.bson.Document> mongoCollection = this.mongoDatabase.getCollection(Collection.TEST_QUESTION);
        BasicDBObject basicDBObject = new BasicDBObject();
        basicDBObject.put("_id", objectId);
        FindIterable<org.bson.Document> findIterable = mongoCollection.find(basicDBObject);
        MongoCursor<Document> mongoCursor = findIterable.iterator();
        TestQuestion testQuestion = null;
        while (mongoCursor.hasNext()){
            String json = mongoCursor.next().toJson();
            testQuestion = JSONObject.parseObject(json, TestQuestion.class);
        }
        return testQuestion;
    }

    /**
     * 根据正则表达式，判断是否有相似的TestQuestion对象
     * @param subjectPattern
     * @param optionPatternList
     * @return
     */
    public List<TestQuestion> findSimilarTestQuestionByRegex(Pattern subjectPattern, List<Pattern> optionPatternList){
        // 加载试题
        MongoCollection<org.bson.Document> testQuestionMongoCollection = this.mongoDatabase.getCollection(Collection.TEST_QUESTION);
        FindIterable<org.bson.Document> testQuestionFindIterable = testQuestionMongoCollection.find();

        // 查找匹配到的对象
        List<TestQuestion> testQuestionList = new ArrayList<>();
        FindSimilarTestQuestionByRegexBlock findSimilarTestQuestionByRegexBlock = new FindSimilarTestQuestionByRegexBlock(subjectPattern, optionPatternList, this, testQuestionList);
        testQuestionFindIterable.forEach(findSimilarTestQuestionByRegexBlock);
        return testQuestionList;
    }

    /**
     * 向mongodb中插入TestQuestion类型对象
     * @param testQuestion
     */
    public void insertTestQuestion(TestQuestion testQuestion){
        org.bson.Document document = testQuestion.toDocument();
        MongoCollection<org.bson.Document> mongoCollection = this.mongoDatabase.getCollection(Collection.TEST_QUESTION);
        mongoCollection.insertOne(document);
    }

    /**
     * 向mongodb中插入DBObject类型对象（json字符串）
     * @param dbObject
     */
    public void insertJSONString(DBObject dbObject, String collectionName){
        MongoCollection<DBObject> mongoCollection = this.mongoDatabase.getCollection(collectionName, DBObject.class);
        mongoCollection.insertOne(dbObject);
    }
}
